package Algorithm.math.graphical;

import Common.Utils.UTFactory;
import org.junit.Test;

import java.util.HashMap;
import java.util.Map;

/**
 * @author 蔚蔚樱
 * @version V1.0
 * @date 2022/10/27 01:24
 * @author-Email micromicrohard@outlook.com
 * @description 检查四个点是否构成矩形
 * 方案一：矩阵的任意三个点符合勾股定理
 * 方案二：
 * * 1，两对"对边"长度的平方相等 （平行四边形）
 * * 2，其中一个内角为直角，勾股定理（一对角线长度的平方等于两直角边长度的平方的和）
 * 方案三：长、宽、对角线 都相等
 * 方案四：对角线相等且互相平分的四边形才是矩形
 * @blogURL
 */
public class CheckRectangle {

    @Test // 验证功能：从数据库获取测试数据，用于单元测试
    public void TestFunc() throws Exception {
        UTFactory.FullTest(this.getClass());
    }

    @Test // 调试功能 : 用于复现错误的测试案例
    public void DoubleTrack() throws Exception {
        String input = "{{0.0,0.0},{0.0,2.0},{2.0,0.0},{2.0,2.0}}";
        String output = "TrueExpr";
        UTFactory.DebugTest(this.getClass(), input, output);
    }

    double threadHold = 0.00001;

    // 方案一：矩阵的任意三个点符合勾股定理
    public boolean PythagoreanTheoremMethod(float[][] matrixPoint) {
        if (!matrixPointCheck(matrixPoint)) {
            return false;
        }

        CalDistanceOfTwoPoint tools = new CalDistanceOfTwoPoint();
        for (int i = 0; i < matrixPoint.length; i++) {
            float[] point1 = matrixPoint[i];
            for (int j = i + 1; j < matrixPoint.length; j++) {
                float[] point2 = matrixPoint[j];
                for (int k = j + 1; k < matrixPoint.length; k++) {
                    double a1 = Math.pow(tools.calMethod(point1, point2), 2);
                    double a2 = Math.pow(tools.calMethod(point1, matrixPoint[k]), 2);
                    double a3 = Math.pow(tools.calMethod(point2, matrixPoint[k]), 2);
                    if (a1 > a2) {
                        double temp = a1;
                        a1 = a2;
                        a2 = temp;
                    }
                    if (a2 > a3) {
                        double temp = a2;
                        a2 = a3;
                        a3 = temp;
                    }
                    double gap = Math.abs(a1 + a2 - a3);
                    // attention: double类型计算，精度存在丢失，需要明确最小容忍范围
                    if (!floatEquals(a1 + a2, a3)) {
                        // 占位符%f 无法精确打印出 double，只能拼接成字符串
                        // System.out.printf("a1=%f,a2=%f,a3=%f,%s \n", a1, a2, a3, "gap=" + gap);
                        return false;
                    }
                }
            }
        }
        return true;
    }

    // 方案三：长、宽、对角线 都相等
    public boolean Method3(float[][] matrixPoint) {
        if (!matrixPointCheck(matrixPoint)) {
            return false;
        }
        float[] p1 = matrixPoint[0];
        float[] p2 = matrixPoint[1];
        float[] p3 = matrixPoint[2];
        float[] p4 = matrixPoint[3];
        CalDistanceOfTwoPoint tools = new CalDistanceOfTwoPoint();

        // 长、宽、对角线 都相等
        float p1_p2 = tools.calMethod(p1, p2);
        float p3_p4 = tools.calMethod(p3, p4);
        if (!floatEquals(p1_p2, p3_p4)) {
            return false;
        }
        float p1_p3 = tools.calMethod(p1, p3);
        float p2_p4 = tools.calMethod(p2, p4);
        if (!floatEquals(p1_p3, p2_p4)) {
            return false;
        }

        float p1_p4 = tools.calMethod(p1, p4);
        float p2_p3 = tools.calMethod(p2, p3);
        return floatEquals(p1_p4, p2_p3);
        //return floatEquals(Math.pow(p1_p2, 2) + Math.pow(p1_p3, 2), Math.pow(p2_p3, 2));
    }

    // 方案四： 对角线相等且互相平分的四边形才是矩形
    public boolean Method4(float[][] matrixPoint) {
        if (!matrixPointCheck(matrixPoint)) {
            return false;
        }
        float[] p1 = matrixPoint[0];
        float[] p2 = matrixPoint[1];
        float[] p3 = matrixPoint[2];
        float[] p4 = matrixPoint[3];
        CalDistanceOfTwoPoint tools = new CalDistanceOfTwoPoint();

        // 找出对角线
        float longest = tools.calMethod(p1, p2);
        float[] longest_mid = {p1[0] / 2 + p2[0] / 2, p1[1] / 2 + p2[1] / 2};
        float p1_p3 = tools.calMethod(p1, p3);
        float p1_p4 = tools.calMethod(p1, p4);
        float diagonal = 0;
        float[] diagonal_mid = null;
        if (p1_p3 > longest) {
            longest = p1_p3;
            diagonal = tools.calMethod(p2, p4);
            longest_mid = new float[]{p1[0] / 2 + p3[0] / 2, p1[1] / 2 + p3[1] / 2};
            diagonal_mid = new float[]{p4[0] / 2 + p2[0] / 2, p4[1] / 2 + p2[1] / 2};
        }
        if (p1_p4 > longest) {
            longest = p1_p4;
            diagonal = tools.calMethod(p2, p3);
            longest_mid = new float[]{p1[0] / 2 + p4[0] / 2, p1[1] / 2 + p4[1] / 2};
            diagonal_mid = new float[]{p3[0] / 2 + p2[0] / 2, p3[1] / 2 + p2[1] / 2};
        }
        // 对角线相等且互相平分的四边形才是矩形
        return diagonal_mid != null &&
                longest == diagonal &&
                longest_mid[0] == diagonal_mid[0] &&
                longest_mid[1] == diagonal_mid[1];
    }

    public boolean matrixPointCheck(float[][] matrixPoint) {
        if (matrixPoint == null || matrixPoint.length != 4) {
            return false;
        }
        // 坐标位数校验 + 坐标去重
        Map<String, Boolean> existMap = new HashMap<>();
        for (float[] ints : matrixPoint) {
            if (ints.length != 2) {
                return false;
            }
            String key = ints[0] + "" + ints[1];
            if (existMap.containsKey(key)) {
                return false;
            }
            existMap.put(key, true);
        }
        return true;
    }

    public boolean floatEquals(double a, double b) {
        if (Math.abs(a - b) < threadHold) {
            return true;
        }
        //System.out.printf("%s, %s\n", "Math.abs(a - b) = " + Math.abs(a - b), " , threadHold = " + threadHold);
        return false;
    }
}
